/**
 * 
 */
package ca.csf.dfc.poo.iu;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Observable;
import java.util.Observer;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import ca.csf.dfc.poo.bots.Robot;
import ca.csf.dfc.poo.bots.RobotGreedy;
import ca.csf.dfc.poo.bots.RobotRandom;
import ca.csf.dfc.poo.eng.Engine;
import ca.csf.dfc.poo.env.Case;

/**
 * Classe représentant le panneau servant à placer les éléments graphiques de l'interface principale.
 * 
 * @author Jean-François Bédard, Marie-Pier Chabot, 
 * Alexandre Paquet Fasys, Claude Roy
 */
public class PanneauEnvironnement extends JPanel
{
	private static final long serialVersionUID = 1L;
	
	/**
	 * Image représentant un robot aléatoire
	 */
	private Icon m_ImageRobotAleatoire;
	
	/**
	 * Image représentant un robot vorace
	 */
	private Icon m_ImageRobotVorace;
	
	/**
	 * Image représentant un robot intelligent
	 */
	private Icon m_ImageRobotIntelligent;
	
	/**
	 * Les chiffres de 0 à 9
	 */
	private Icon m_chiffre0;
	private Icon m_chiffre1;
	private Icon m_chiffre2;
	private Icon m_chiffre3;
	private Icon m_chiffre4;
	private Icon m_chiffre5;
	private Icon m_chiffre6;
	private Icon m_chiffre7;
	private Icon m_chiffre8;
	private Icon m_chiffre9;
	
	/**
	 * Le panneau contenant les cases de l'environnement et les robots
	 */
	private PanneauDessin m_PanneauDessin;
	
	/**
	 * Le panneau contenant les images reliées à la légende
	 */
	private PanneauLegende m_PanneauLegende;
	
	/**
	 * Pour ajouter un scroll à PanneauDessin
	 */
	private JScrollPane m_ScrPanneau;
	
	/**
	 * L'engin régissant la simulation
	 */
	private Engine m_Engine;
	
	/**
	 * Dimension d'une case carrée
	 */
	private int m_Dimension;
	
	/**
	 * Nombre de lignes de l'environnement
	 */
	private int m_nbLignes;
	
	/**
	 * Nombre de colonnes de l'environnement
	 */
	private int m_nbColonnes;
	
	//Constructeur par défaut
	public PanneauEnvironnement()
	{
		super();
		this.setSize(550, 550);
		this.setLayout(new BorderLayout());

		//le chemin pour les images de robots
		m_ImageRobotAleatoire = new ImageIcon(getClass().getResource("/res/Images/robotAleatoire.jpg"));
		m_ImageRobotVorace = new ImageIcon(getClass().getResource("/res/Images/robotVorace.jpg"));
		m_ImageRobotIntelligent = new ImageIcon(getClass().getResource("/res/Images/robotIntelligent.jpg"));
		
		//le chemin pour les images de chiffres
		m_chiffre0 = new ImageIcon(getClass().getResource("/res/Images/chiffre0.gif"));
		m_chiffre1 = new ImageIcon(getClass().getResource("/res/Images/chiffre1.gif"));
		m_chiffre2 = new ImageIcon(getClass().getResource("/res/Images/chiffre2.gif"));
		m_chiffre3 = new ImageIcon(getClass().getResource("/res/Images/chiffre3.gif"));
		m_chiffre4 = new ImageIcon(getClass().getResource("/res/Images/chiffre4.gif"));
		m_chiffre5 = new ImageIcon(getClass().getResource("/res/Images/chiffre5.gif"));
		m_chiffre6 = new ImageIcon(getClass().getResource("/res/Images/chiffre6.jpg"));
		m_chiffre7 = new ImageIcon(getClass().getResource("/res/Images/chiffre7.gif"));
		m_chiffre8 = new ImageIcon(getClass().getResource("/res/Images/chiffre8.gif"));
		m_chiffre9 = new ImageIcon(getClass().getResource("/res/Images/chiffre9.png"));
		
		//On initialise notre panneau
		m_PanneauDessin = new PanneauDessin();
		
		m_ScrPanneau = new JScrollPane(m_PanneauDessin,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		m_PanneauLegende = new PanneauLegende();
		
		//On force le Panneau dessin à se repainter
		this.revalidate();

		this.add(m_ScrPanneau,BorderLayout.CENTER);
		this.add(m_PanneauLegende,BorderLayout.EAST);
		
	}
	
	/**
	 * Retourne le PanneauDessin.
	 * @return le PanneauDessin
	 */
	public PanneauDessin getPanneauDessin()
	{
		return this.m_PanneauDessin;
	}
	
	/**
	 * Retourne la dimension désirée du PanneauDessin
	 * @return la dimension désirée du PanneauDessin
	 */
	
	public Dimension getPreferredSize()
	{
		return new Dimension(this.m_nbColonnes*this.m_Dimension,this.m_nbLignes*m_Dimension);
	}

	/**
	 * Retourne le engine.
	 * @return le engine
	 */
	public Engine getEngine()
	{
		return this.m_Engine;
	}

	/**
	 * Pour modifier le engine.
	 * @param p_engine Nouvelle valeur.
	 */
	public void setEngine(Engine p_engine)
	{
		this.m_Engine = p_engine;
	}
	
	
	/**
	 * Construction de l'environnement (sans les robots)
	 * @param p_Engine L'engin régissant la simulation
	 * @param p_grap Interface pour représenter des éléments graphiques
	 */
	private void construireEnvironnement (Engine p_Engine, Graphics p_grap)
	{	
		this.m_nbColonnes = p_Engine.getEnvironnement().getWidth();
		this.m_nbLignes = p_Engine.getEnvironnement().getHeight();		
		
		this.definirGrandeurCases();
	
		//Pour colorer les cases
		for (int i = 0 ; i < this.m_nbLignes ; i++)
		{
			for (int j = 0 ; j < this.m_nbColonnes ; j++)
			{
				if (p_Engine.getEnvironnement().getMap() [i][j] == Case.INTERDIT)
				{
					p_grap.setColor(Color.RED);

				}
				else if (p_Engine.getEnvironnement().getMap() [i][j] == Case.PRISE)
				{
					p_grap.setColor(Color.GREEN);

				}
				else if (p_Engine.getEnvironnement().getMap() [i][j] == Case.TAPIS)
				{
					p_grap.setColor(Color.YELLOW);

				}
				else if (p_Engine.getEnvironnement().getMap() [i][j] == Case.PLANCHER)
				{
					p_grap.setColor(Color.WHITE);				
				}
				p_grap.fillRect(50 + j*this.m_Dimension, 50+i*this.m_Dimension,
						this.m_Dimension, this.m_Dimension);		
			}
		}
		
		//pour les lignes verticales
		p_grap.setColor(Color.BLACK);
		for (int i = 0 ; i < m_nbColonnes+1 ; i++)
		{	

			p_grap.drawLine(50 + i*this.m_Dimension, 50, 50 + i*this.m_Dimension, (this.m_nbLignes)*this.m_Dimension+50);	
		}
		
		//pour le lignes horizontales
		for (int i = 0 ; i < m_nbLignes+1 ; i++)
		{
			p_grap.drawLine(50, 50 + i*this.m_Dimension, (this.m_nbColonnes)*this.m_Dimension+50, 50 + i*this.m_Dimension);
		}
	}
	
	/**
	 * Fonction servant à déterminer la grandeur des cases carrées du panneau en fonction
	 * du nombre de lignes et de colonnes de l'environnement
	 */
	private void definirGrandeurCases()
	{	
		//On s'assure que notre envirronnement est carré.
		if (this.m_nbLignes > this.m_nbColonnes)
		{
			this.m_Dimension = 550/this.m_nbLignes;
		}
		else
		{
			this.m_Dimension = 550/this.m_nbColonnes;
		}
		
		//On compare avec nos grandeur max et minimum
		if (this.m_Dimension > PanneauImage.TAILLE_MAXIMUM)
		{
			this.m_Dimension = PanneauImage.TAILLE_MAXIMUM;
		}
		
		if (this.m_Dimension < PanneauImage.TAILLE_MINIMUM)
		{
			this.m_Dimension = PanneauImage.TAILLE_MINIMUM;
		}
	}
		
	/**
	 * @author Jean-François Bédard, Marie-Pier Chabot, 
	 * Alexandre Paquet Fasys, Claude Roy
	 *
	 * Classe représentant le panneau servant à placer les éléments graphiques de la légende
	 */
	private class PanneauLegende extends JPanel
	{
		private static final long serialVersionUID = 7955961979655722405L;

		public PanneauLegende()
		{
			super();
			this.setSize(new Dimension(100,500));
			this.setPreferredSize(new Dimension(100,500));
		}
		
		//Pour représenter les compsantes graphiques (La légendes et les images de robots)
		@Override
		protected void paintComponent (Graphics p_Graphic)
		{
			super.paintComponent(p_Graphic);
			
			//Légende pour la couleur des cases
			p_Graphic.setColor(Color.WHITE);
			p_Graphic.fillRect(5, 235, 40, 40);
			p_Graphic.setColor(Color.YELLOW);
			p_Graphic.fillRect(5, 292, 40, 40);	
			p_Graphic.setColor(Color.GREEN);
			p_Graphic.fillRect(5, 349, 40, 40);
			p_Graphic.setColor(Color.RED);
			p_Graphic.fillRect(5, 406, 40, 40);
			
			//Légende pour les types de robots
			PanneauEnvironnement.this.m_ImageRobotAleatoire.paintIcon 
			(this, p_Graphic, 0, 515);
			PanneauEnvironnement.this.m_ImageRobotVorace.paintIcon 
			(this, p_Graphic, 0, 575);
			PanneauEnvironnement.this.m_ImageRobotIntelligent.paintIcon 
			(this, p_Graphic, 0, 635);
		}
	}
	
	/**
	 * @author Jean-François Bédard, Marie-Pier Chabot, 
	 * Alexandre Paquet Fasys, Claude Roy
	 *
	 * Classe représentant le panneau servant à placer les éléments graphiques de l'interface principale, excluant la légende
	 */
	public class PanneauDessin extends JPanel implements Observer
	{
		private static final long serialVersionUID = 1L;
		/**
		 * Signal avertissant le panneau (observateur) d'un changement dans l'engin (observé)
		 */
		private Signal m_Signal;
		
		public PanneauDessin()
		{
			//Construction et initialisation du signal
			m_Signal = new Signal();
			this.init(m_Signal);
		}
		
		//Pour représenter les compsantes graphiques
		@Override
		protected void paintComponent (Graphics p_Graphic)
		{	
			super.paintComponent(p_Graphic);
			
			//à l'ouverture de l'interface principale, le panneau est vide (rectangle blanc)
			if (PanneauEnvironnement.this.getEngine() == null)
			{
				p_Graphic.setColor(Color.WHITE);
				p_Graphic.fillRect(50, 50, 600, 600);	
			}
			else 
			{		
				PanneauEnvironnement.this.construireEnvironnement(PanneauEnvironnement.this.getEngine(), p_Graphic);
				
				//On ajoute les robots dans le panneau (s'il y en a).  
				int compteur = 1;
				for (Robot robot:PanneauEnvironnement.this.getEngine().getListRobots())
				{
					int largeurImage = 0;
					int hauteurImage = 0;
					if (robot instanceof RobotRandom)
					{
						largeurImage = PanneauEnvironnement.this.m_ImageRobotAleatoire.getIconWidth();
						hauteurImage = PanneauEnvironnement.this.m_ImageRobotAleatoire.getIconHeight();
					}
					else if (robot instanceof RobotGreedy)
					{
						largeurImage = PanneauEnvironnement.this.m_ImageRobotVorace.getIconWidth();
						hauteurImage = PanneauEnvironnement.this.m_ImageRobotVorace.getIconHeight();
					}
					else
					{
						largeurImage = PanneauEnvironnement.this.m_ImageRobotIntelligent.getIconWidth();
						hauteurImage = PanneauEnvironnement.this.m_ImageRobotIntelligent.getIconHeight();
					}
					
					//Le position du robot dans le panneau sera deux coordonnées : x et y
					int [] positionRobotPanneau = new int[2];
					positionRobotPanneau = placerRobot (robot, largeurImage, hauteurImage);
					if (robot instanceof RobotRandom)
					{
						PanneauEnvironnement.this.m_ImageRobotAleatoire.paintIcon 
									(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
					}
					else if (robot instanceof RobotGreedy)
					{
						PanneauEnvironnement.this.m_ImageRobotVorace.paintIcon 
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
					}
					else
					{
						PanneauEnvironnement.this.m_ImageRobotIntelligent.paintIcon 
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						
					}
					
					//Pour numéroter les robots
					switch (compteur)
					{
					case 1:
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						break;
					case 2 :
						PanneauEnvironnement.this.m_chiffre2.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						break;
					case 3 :
						PanneauEnvironnement.this.m_chiffre3.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						break;
					case 4 :
						PanneauEnvironnement.this.m_chiffre4.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						break;
					case 5 :
						PanneauEnvironnement.this.m_chiffre5.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						break;
					case 6 :
						PanneauEnvironnement.this.m_chiffre6.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						break;
					case 7 :
						PanneauEnvironnement.this.m_chiffre7.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						break;
					case 8 :
						PanneauEnvironnement.this.m_chiffre8.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						break;
					case 9 :
						PanneauEnvironnement.this.m_chiffre9.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						break;
					case 10:
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						PanneauEnvironnement.this.m_chiffre0.paintIcon
						(this, p_Graphic, positionRobotPanneau[0]+35, positionRobotPanneau[1]);
						break;
					case 11:
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0]+35, positionRobotPanneau[1]);
						break;
					case 12:
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						PanneauEnvironnement.this.m_chiffre2.paintIcon
						(this, p_Graphic, positionRobotPanneau[0]+35, positionRobotPanneau[1]);
						break;
					case 13:
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						PanneauEnvironnement.this.m_chiffre3.paintIcon
						(this, p_Graphic, positionRobotPanneau[0]+35, positionRobotPanneau[1]);
						break;
					case 14:
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						PanneauEnvironnement.this.m_chiffre4.paintIcon
						(this, p_Graphic, positionRobotPanneau[0]+35, positionRobotPanneau[1]);
						break;
					case 15:
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						PanneauEnvironnement.this.m_chiffre5.paintIcon
						(this, p_Graphic, positionRobotPanneau[0]+35, positionRobotPanneau[1]);
						break;
					case 16:
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						PanneauEnvironnement.this.m_chiffre6.paintIcon
						(this, p_Graphic, positionRobotPanneau[0]+35, positionRobotPanneau[1]);
						break;
					case 17:
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						PanneauEnvironnement.this.m_chiffre7.paintIcon
						(this, p_Graphic, positionRobotPanneau[0]+35, positionRobotPanneau[1]);
						break;
						
					case 18:
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						PanneauEnvironnement.this.m_chiffre8.paintIcon
						(this, p_Graphic, positionRobotPanneau[0]+35, positionRobotPanneau[1]);
						break;
					case 19:
						PanneauEnvironnement.this.m_chiffre1.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						PanneauEnvironnement.this.m_chiffre9.paintIcon
						(this, p_Graphic, positionRobotPanneau[0]+35, positionRobotPanneau[1]);
						break;
					case 20:
						PanneauEnvironnement.this.m_chiffre2.paintIcon
						(this, p_Graphic, positionRobotPanneau[0], positionRobotPanneau[1]);
						PanneauEnvironnement.this.m_chiffre0.paintIcon
						(this, p_Graphic, positionRobotPanneau[0]+35, positionRobotPanneau[1]);
						break;				
					}				
					compteur++;
				}
				
			}
		}
		
		
		/**
		 * Cette fonction place un robot dans la grille  (environnement) en fonction de ses coordonnées
		 * 
		 * @param p_robot :	Le robot à placer 
		 * @param p_largeurImage :	La largeur de l'image du robot
		 * @param p_hauteurImage :	La hauteur de l'image du robot
		 * @return		Une paire de coordonnées situant le robot sur la grille
		 */
		
		private int [] placerRobot (Robot p_robot, int p_largeurImage, int p_hauteurImage)
		{
			int [] positionRobotPanneau = new int [2];
			int positionX = p_robot.getPosition().m_x;
			int positionY = p_robot.getPosition().m_y;
			int largeurPanneau = PanneauEnvironnement.this.m_nbColonnes*PanneauEnvironnement.this.m_Dimension;
			int hauteurPanneau = PanneauEnvironnement.this.m_nbLignes*PanneauEnvironnement.this.m_Dimension;
			int largeurEnvironnement = PanneauEnvironnement.this.getEngine().getEnvironnement().getWidth();
			int hauteurEnvironnement = PanneauEnvironnement.this.getEngine().getEnvironnement().getHeight();	
			
			//la position horizontale de l'image
			int positionPanneauX = 50+largeurPanneau/largeurEnvironnement*positionY
			+ largeurPanneau/largeurEnvironnement/2 - p_largeurImage/2;
			
			//la position verticale de l'image
			int positionPanneauY = 50+hauteurPanneau/hauteurEnvironnement*positionX
			+ hauteurPanneau/hauteurEnvironnement/2 - p_hauteurImage/2;
				
			positionRobotPanneau [0] = positionPanneauX;
			positionRobotPanneau [1] = positionPanneauY;		
			return positionRobotPanneau;		
		}
		
		/**
		 * Pour ajouter des observateurs
		 * @param lSigAObserver liste d'observateurs
		 */
		private void init(Signal lSigAObserver)
		{
		    //Ajout du PanneauEnvironnement courant comme observateur
			lSigAObserver.addObserver(this);
		}
		
		/**
		 * Lorsqu'il y a un changement dans l'engin, on redessine le PanneauEnvironnement, 
		 * incluant ses robots
		 */
		public void update(Observable observable, Object objectConcerne)
		{
			repaint();
			revalidate();
			PanneauDessin.this.repaint();
			PanneauDessin.this.revalidate();
		}
		
		/**
		 * Retourne le signal.
		 * @return le signal
		 */
		public Signal getSignal()
		{
			return this.m_Signal;
		}

		
		/**
		 * Tous les robots de l'environnement se déplacent
		 */
		public void faireMouvement()
		{
			PanneauEnvironnement.this.getEngine().oneStep();			
			this.getSignal().setData();			
		}

		/* (non-Javadoc)
		 * @see javax.swing.JComponent#getPreferredSize()
		 */
		@Override
		/**
		 * Methode qui retourne la dimension que le panneau doit avoir.
		 */
		public Dimension getPreferredSize()
		{
			return new Dimension(PanneauEnvironnement.this.m_nbColonnes*PanneauEnvironnement.this.m_Dimension+100,PanneauEnvironnement.this.m_nbLignes*PanneauEnvironnement.this.m_Dimension+100);
		}
		
		
	}
}